home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c++ / 375 < prev    next >
Encoding:
Text File  |  1996-08-06  |  11.5 KB  |  323 lines

  1. Path: engnews1.Eng.Sun.COM!taumet!clamage
  2. From: dirk@becker.adviser.com (Dirk Becker)
  3. Newsgroups: comp.std.c++
  4. Subject: Re: class.union questions
  5. Date: 10 Feb 1996 15:39:23 GMT
  6. Organization: ?
  7. Approved: clamage@eng.sun.com (comp.std.c++)
  8. Message-ID: <v01530501ad3e247b1270@[194.163.74.11]>
  9. NNTP-Posting-Host: taumet.eng.sun.com
  10. Mime-Version: 1.0
  11. Content-Type: text/plain; charset="us-ascii"
  12. X-Sender: dirk@194.163.74.12
  13. Cc: kanze@lts.sel.alcatel.de
  14. Content-Length: 11074
  15. Originator: clamage@taumet
  16.  
  17. Sorry to be late with this, but I just learned my newsserver
  18. does not yet deliver my posts.
  19.  
  20. The first replies to my (DB) original posting seem to have the same
  21. objection against my interpretation of b). This is my major problem,
  22. so I put it first now.
  23.  
  24. James Kanze (JK) and John Max Skaller (JS) wrote:
  25.  
  26. From the WP: [class.union]
  27.  
  28. b) "An object of a class with a non-trivial default constructor
  29.      (_class.ctor_), a non-trivial copy constructor (_class.copy_),
  30.      a non-trivial destructor (_class.dtor_), or a non-trivial copy
  31.      assignment operator (_over.ass_, _class.copy_) cannot be a member
  32.      of a union,"
  33.  
  34. DB> This is a major reduction of the restrictions found in ARM, where all
  35. DB> kinds of constructors or assignment operators were excluded. Here is
  36. DB> also a note to give the explanation by the assumption, any member
  37. DB> functions and especially assignments would usually expect a correctly
  38. DB> constructed object.
  39.  
  40. JS>       No. It is merely a more precise statement of the same
  41. JS> restrictions using more technical terminology.
  42.  
  43. JK> This is, in fact, exactly the restriction in the ARM.  All that has
  44. JK> changes is the way things are described.  In the ARM, classes may or
  45. JK> may not have constructors (destructors, assignment operators). In the
  46. JK> current standard, *EVERY* class/struct has a copy constructor, an
  47. JK> assignment operator and a destructor; the distinction is that some of
  48. JK> these are trivial.
  49.  
  50. I still disagree totally. Please tell me what I'm reading wrong.
  51.  
  52. The ARM (mine is an early edition, 1990) does a complete restriction
  53. against *any* constructor, destructor or user-defined assignment for
  54. union member objects. (Section 9.5, page 182). The only explanation for
  55. this rule was already summarized in my original posting, quoted above;
  56. it has nothing to do with bitwise copy.
  57.  
  58. The WP indeed allows member objects with a rich set of constructors
  59. and assignment operators. It does only <g> cripple the 4 most commonly
  60. used special member functions, exactly naming them, into trivialness.
  61. - default constructor
  62. - destructor
  63. - copy constructor
  64. - copy assignment
  65. I assume this exact enumeration implies all other variants of constructor
  66. and assignment in member objects are free for user defined versions.
  67. So the following sample seems perfectly legal with the WP, not with ARM.
  68. The commented lines are the trivialness-required special member functions.
  69.  
  70. class Bar {
  71. public:
  72. //  Bar();                          // trivial default constructor
  73. //  Bar(const Bar&);                // trivial copy constructor
  74. //  ~Bar();                         // trivial destructor
  75. //  Bar& operator = (const Bar&);   // trivial copy assignment
  76.  
  77.     // plain member function - no problem
  78.     Bar& operator_assign(const Bar&);
  79.  
  80.     // some other constructors - I see no problem here
  81.     Bar(int);
  82.     Bar(float);
  83.  
  84.     // several other simple assignments are allowed
  85.     Bar& operator = (int);
  86.     Bar& operator = (float);
  87.  
  88.     // these are assignments too, see ARM 5.17 or [expr.ass]
  89.     Bar& operator += (const Bar&);
  90.     Bar& operator -= (const Bar&);
  91.     Bar& operator *= (const Bar&);
  92.     Bar& operator /= (const Bar&);
  93.  
  94.     // ... data members etc.
  95. };
  96.  
  97. union Foo {
  98.     Bar  bar;
  99.     // ... others
  100. };
  101.  
  102. DB> So you can have any special assignment operator or constructor for
  103. DB> your member objects, any but the most common and useful ones.
  104.  
  105. JK> Correct. The reason is simple: assignment, copy, default construction
  106. JK> and destruction of a union must be correctly defined without the
  107. JK> compiler knowing which element the union actually contains. The set
  108. JK> of forbidden operators are those that the compiler might be called
  109. JK> upon to use in implicitly generated code.
  110.  
  111. But why would you like to provide your own constructor and assignments?
  112. Maybe because you have added some side effects, like range checking or
  113. trigger a reference counter.
  114. If you only use arguments matching your custom routines, this will work
  115. fine. But if you accidentally assign one Foo.bar to another, your
  116. side-effects won't take place because the WP prevented your custom copy
  117. assignment operator.
  118. It is even impossible to hide the unwanted implicit constructors and
  119. copy assignment into privacy, to make your compiler produce an error
  120. message.
  121.  
  122. Foo     foo1;
  123. Foo     foo2;
  124.  
  125. foo1.bar = 4711;        // applies your side-effects
  126. foo2.bar = foo1.bar;    // just trivial assignment here due to WP
  127.  
  128. -----
  129.  
  130. a)  "A union shall not have base classes. A union shall not be used as
  131.       a base class."
  132.  
  133. JK> Without this rule, you either break the address rule, or you impose
  134. JK> some special class layout on unions.
  135.  
  136. The union has no special class layout? I would say it is very special.
  137. "a class whose member objects all begin at offset zero"
  138.  
  139. -----
  140.  
  141. /* my sample of union inheritance */
  142.  
  143. JK> This is generally handled better by an abstract base class and
  144. JK> virtual functions.
  145.  
  146. Sure, I like polymorphic objects. But if you have a vast amount of
  147. really small objects you may get tempted to use the reduced footprint
  148. of a (1 or 2 byte) tag instead of a sizeof(ptr) vptr.
  149. It is also slightly faster to load these unions from a binary file
  150. than from a stream, allocate, dispatch and construct every single
  151. object and retrieve every single member.
  152.  
  153. -----
  154.  
  155. /* union with longlong as member */
  156.  
  157. DB> If you are lucky to have some native long long datatype, then this
  158. DB> would be legal code. If you already had to implement your own
  159. DB> class longlong, now you lost the chance to use it (here).
  160.  
  161. JK> This is a problem, but... how would the compiler know when to call
  162. JK> the constructor/destructor of your longlong?
  163.  
  164. Sorry for the wrong sample, longlong may work with trivial c/dtor and
  165. copy operations. The same is with some class Complex.
  166.  
  167. Let's reconsider a class "string" and reference-counter features as
  168. sideeffects. The answer for your question - how would the compiler
  169. know? - came with my conclusion as quoted below: Just tell him.
  170. Here the union constructor itself gets responsible for construction as
  171. the correct union variant - e.g. choose the correct discriminator tag,
  172. like "empty".
  173.  
  174. DB> I would generally prefer " ... constructors and destructor of member
  175. DB> objects are ignored, if not explicitly called by the union's ctor/dtor.
  176. DB> The union's implicit default copy constructor / assignment does a
  177. DB> binary copy instead of memberwise copy. Objects <containing a vptr>
  178. DB> cannot be member of a union" - Please pardon my shortcut on vptrs.
  179.  
  180. The missing sample for this:
  181.  
  182. class Member {
  183. public:
  184.   Member();
  185.   // ...
  186. };
  187. class Other {
  188. public:
  189.   Other();
  190.   // ...
  191. };
  192.  
  193. union Union {
  194.   Union();
  195.   Union(int);
  196.   // ...
  197.   Member m;
  198.   Other  o;
  199. };
  200.  
  201. Union::Union()
  202. { // call none of the base member constructors
  203. }
  204.  
  205. // call Member::Member() using a wellknown notation
  206. Union::Union(int a)
  207. : m()
  208. { }
  209.  
  210. // deluxe variant - but this would mean a severe extension
  211. Union::Union(int tag)
  212. : tag==1 ? m()  // call Member::Member()
  213. : tag==2 ? o()  // otherwise call Other::Other()
  214. { }
  215.  
  216. -----
  217.  
  218. c) "A union can be thought of as a class"
  219.  
  220. DB> Here you accept the implications of 12.8.8 and 12.8.13 on implicitly
  221. DB> defined copy constructor and copy assignment. The already trivial
  222. DB> copy constructor/assignment of the member objects will then result
  223. DB> in one large repetition of copies from and to the same memory locations.
  224. DB> To avoid this behaviour I would strongly recommend to implement your
  225. DB> own copy constructor or assignment whenever you use a union, because a
  226. DB> memberwise copy is usually not desired.
  227.  
  228. JK> Basically, if you study the restrictions on unions carefully, the
  229. JK> rules are such that a bitwise copy *must* be legal for assignment and
  230. JK> copy construction.  This is the only type of copy the compiler can
  231. JK> cope with in the absense of a discriminator to tell it which element
  232. JK> of the union is valid.
  233.  
  234. JK> IMHO: if you feel that your union needs a copy constructor or an
  235. JK> assignment operator, you are probably doing something wrong, in the
  236. JK> sense that you are trying to use unions in a way that they are not
  237. JK> intended.  (As they are defined in the standard. If they were defined
  238. JK> differently, they might have different reasonable uses.)
  239.  
  240. I knew, but some compiler implementors forget their homework here.
  241. If for any reason (generated source) you have a union with lots of
  242. members, you may accidentally get lots of redundant code. This is
  243. another reason for implicit bitwise copy.
  244.  
  245. And if the trivialness requirement were removed from the copy
  246. operations, like in my (very draft) replacement text quoted above,
  247. you would also loose the equivalence.
  248.  
  249. From a discussion outside this newsgroup I finally got a hint on the
  250. intention behind the new restrictions: They should ensure a bitwise
  251. copy of the union will copy the current union member correctly.
  252. This is achieved by forcing bitwise copy for any potential member.
  253.  
  254. Why did you then not stay just with the POD union? With the
  255. differentiation between POD union and non-POD union you already
  256. got the higher degree of complexity, only to undo this with lots
  257. of additional words.
  258.  
  259. My first incident with this problem went what I would call a
  260. user's way instead of the implementor's sight: How can we use
  261. it? Instead of "How to infer the implicit implementation?"
  262. Here I felt invited by the WP to use most of the member object
  263. assignments and than fell into the trivialness trap.
  264.  
  265. If your intention is bitwise copy as implicit copy for the union
  266. itself, why not just call it by its real name instead of hiding
  267. behind "trivialness"?
  268. "The implicit union copy constructor and copy assignment apply
  269. bitwise copy."
  270. No trivialness restrictions on the member objects!
  271. If someone then decides to have member objects with other copy
  272. constructor or assignment semantics, he/she just has to provide
  273. own union copy operations.
  274.  
  275. -----
  276. d)
  277.  
  278. DB> Why is there no anonymous struct?
  279.  
  280. JS> The committee (as a body) does not find arguments for
  281. JS> orthogonal design appealing. It is hard to demonstrate
  282. JS> why orthogonal design is good to those who have little
  283. JS> experience with orthogonal systems -- most of us,
  284. JS> considering the horrid systems we're forced to work with
  285. JS> most of the time.
  286.  
  287. JK> Agreed here. Although I really don't see it as worth the bother.
  288. JK> (I could do without anonymous unions, too.)
  289.  
  290. You won't need the anonymous struct, because you already said you
  291. don't use unions.
  292.  
  293. -----
  294.  
  295. Some new questions:
  296.  
  297. e) "At most one of the member objects can be stored in a union at
  298.     any time."
  299.  
  300. Has anybody already thought about the memberwise implicit operations in
  301. regard to this rule?
  302. OK, we'll meet again at the bitwise copy, but this is at least nowhere
  303. explicitly mentioned in the WP.
  304.  
  305. -----
  306.  
  307. f)
  308.  
  309. Why is [class.mem] 15 restricted to POD structs as union members?
  310. vptrs are already excluded for union members, and I would still
  311. ask to exclude them when dropping the trivialness.
  312.  
  313. ------------------------------------------------------------------
  314. Dirk Becker                                dirk@becker.adviser.com
  315. Harderweg 76, 22549 Hamburg, Germany          Tel. +49 40 80783143
  316.  
  317.  
  318.  
  319. [ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  320.   Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  321.   summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  322. ]
  323.